package Syntax_Anlayzer;

import java.util.*;

public class PredictiveTable {
    public static Map<String, Map<String, String>> table = new HashMap<>();
//First first, Follow follow, Map<String, Set<List<String>>> production
    public PredictiveTable() {
        // 构建预测分析表
        for (Map.Entry<String, Set<List<String>>> prodEntry : Init.Production.entrySet()) {
            String nonTerminal = prodEntry.getKey();
            for (List<String> productionRHS : prodEntry.getValue()) {
                // 对于产生式左侧的非终结符
                if (!productionRHS.isEmpty()) {
                    String firstSymbol = productionRHS.get(0);
                    if (firstSymbol != null && !firstSymbol.equals("ε")) {
                        Set<String> firstSet = First.getFirstSet(firstSymbol);
                        for (String terminal : firstSet) {
                            if (terminal != null && !terminal.equals("ε")) {
                                addEntry(nonTerminal, terminal, productionRHS);
                            }
                        }
                    }
                    // 如果第一个符号是ε，或者后续符号的FIRST集包含ε
                    if (productionRHS.size() > 1) {
                        String nextSymbol = productionRHS.get(1);
                        if (Init.V_N.contains(nextSymbol)) {
                            Set<String> followSet = Follow.getFollowSet(nextSymbol);
                            for (String terminal : followSet) {
                                if (terminal != null && !terminal.equals("ε")) {
                                    addEntry(nonTerminal, terminal, productionRHS);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private void addEntry(String nonTerminal, String terminal, List<String> productionRHS) {
        if (!table.containsKey(nonTerminal)) {
            table.put(nonTerminal, new HashMap<>());
        }
        Map<String, String> terminalMap = table.get(nonTerminal);
        terminalMap.put(terminal, productionRHS.toString());
    }

    public static void displayTable() {
        // 显示预测分析表
        for (Map.Entry<String, Map<String, String>> entry : table.entrySet()) {
            String nonTerminal = entry.getKey();
            Map<String, String> row = entry.getValue();
            System.out.print(nonTerminal + ": ");
            for (Map.Entry<String, String> cell : row.entrySet()) {
                System.out.print(cell.getKey() + " -> " + cell.getValue() + ", ");
            }
            System.out.println();
        }
    }

    private Deque<String> stack = new ArrayDeque<>();
    public List<String> inputTokens=new ArrayList<>();
    private int inputPos = 0;
    private int step = 0;

    public void parse(List<String> inputTokens) {
        this.inputTokens = inputTokens;
        while (!stack.isEmpty() && inputPos < inputTokens.size()) {
            String topSymbol = stack.peek();
            String inputSymbol = inputTokens.get(inputPos);

            if (table.containsKey(topSymbol) && table.get(topSymbol).containsKey(inputSymbol)) {
                // 归约操作
                String production = table.get(topSymbol).get(inputSymbol);
                reduce(topSymbol, inputSymbol, production);
            } else if (topSymbol.equals(inputSymbol)) {
                // 移进操作
                move(topSymbol, inputSymbol);
            } else {
                // 错误处理
                error(topSymbol, inputSymbol);
                break;
            }
        }
    }

    private void reduce(String nonTerminal, String terminal, String production) {
        printStep("reduction", nonTerminal, terminal, production);
        // 弹出产生式右侧的符号
        String[] rhs = production.split(" ");
        for (int i = rhs.length - 1; i >= 0; i--) {
            stack.pop();
        }
        // 推入产生式左侧的非终结符
        stack.push(nonTerminal);
    }

    private void move(String topSymbol, String inputSymbol) {
        printStep("move", topSymbol, inputSymbol);
        stack.pop();
        stack.push(inputSymbol);
        inputPos++;
    }

    private void error(String topSymbol, String inputSymbol) {
        printStep("error", topSymbol, inputSymbol);
    }

    private void printStep(String action, String topSymbol, String inputSymbol) {
        System.out.println("[" + (step++) + "]\t" + topSymbol + "#" + inputSymbol + "\t" + action);
    }

    private void printStep(String action, String topSymbol, String inputSymbol, String production) {
        System.out.println("[" + (step++) + "]\t" + topSymbol + "#" + inputSymbol + "\t" + action + " by rule " + production);
    }

}